package com.org.khtn.data;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

public class DataTables {
	public final String className = "DataTables:";
	Vector dataTables;
	String fileLocation;
	Vector tableNames;
	String name;

	public DataTables(Data data) {
		dataTables = new Vector();
		tableNames = new Vector<String>();
		Load(data);
		name = data.getName();
	}
	public String getName()
	{
		return name;
	}
	public DataTables(String fullPath) {
		fileLocation = fullPath;
		dataTables = new Vector();
		tableNames = new Vector<String>();
		Load();
	}

	public void Load(Data data) {
		fileLocation = data.getPath() + data.getName();
		Load();

	}

	Map<String, Map<String, Map<String, String>>> myData;
	List<DataTableDefination> dataDefines;

	public void clear() {
		dataTables.clear();
		tableNames.clear();
	}

	private void Load() {
		try {
			loadData();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Doc file .define de xem cau truc cua database
	 * 
	 * @throws IOException
	 */
	public void loadData() throws IOException {
		final String methodName = "loadData():";
		Type listOfTestObject = new TypeToken<List<DataTableDefination>>() {
		}.getType();
		Gson gson = new Gson();
		myData = getData();
		// // // System.out.println(className+methodName+"myData "+myData);

		// System.out.println("DatabaseDefination : LoadDataDefine() :" +
		// fileLocation);
		String defineLocation = fileLocation + ".define";
		Reader isReader = new InputStreamReader(new FileInputStream(
				(defineLocation)));
		dataDefines = Collections
				.synchronizedList((List<DataTableDefination>) gson.fromJson(
						isReader, listOfTestObject));
		// // //
		// System.out.println("DataTables : LoadDataDefine() : list2.size: "+ //
		// list2.size());
		// System.out.println(className + methodName + "gson.toJson(list2): " +
		// gson.toJson(dataDefines));

		for (DataTableDefination dt : dataDefines) {
			// // //
			// System.out.println("DataTables : LoadDataDefine() : dt.getTableName(): "+
			// dt.getTableName());
			Fields temp3 = null;
			if (dt.getVarName() != null) {
				temp3 = new Fields(dt.getVarName(), dt.getTypes());
				tableNames.add(dt.getTableName());
			}
			Table table = new Table(temp3, dt.getTableName());
			// // //
			// System.out.println(className+methodName+"myData.get(table.getName()) "+myData.get(table.getName()));
			table.setData(myData.get(table.getName()));
			table.setPrimaryKey(dt.getPk());
			// // // System.out.println(table.getName());
			// // //
			// System.out.println(className+methodName+"table.getData() "+table.getData());

			dataTables.add(table);
		}

		// // // System.out.println(dataDefines.size());

	}

	/**
	 * Thay Ä‘á»•i táº¥t cáº£ cÃ¡c record cÃ³ field = fieldName
	 * 
	 * @param tableName
	 *            tÃªn table
	 * @param fieldName
	 *            tÃªn field cáº§n edit
	 * @param fieldValue
	 *            giÃ¡ trá»‹ thay Ä‘á»•i
	 */
	public void editValueAllRecord(String tableName, String fieldName,
			String fieldValue) {
		final String methodName = "editValueAllRecord:";

		Table temp = getTable(tableName);
		temp.editValueAllRecord(fieldName, fieldValue);
		// // // System.out.println(className +methodName+"myData 0"+myData );

		System.out.println(className + methodName + "temp.getData()1:"
				+ temp.getData());
		System.out.println(className + methodName + "tableName:" + tableName);

		myData.put(tableName, temp.getData());
		// // // System.out.println(className +methodName+"myData 1"+myData );

		save(myData, fileLocation + ".json");
	}

	public void save(Object data, String dataLocation) {
		Gson gson = new Gson();
		Writer osWriter = null;
		try {
			osWriter = new OutputStreamWriter(
					new FileOutputStream(dataLocation));
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		gson.toJson(data, osWriter);
		try {
			osWriter.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Doc file .json de load du lieu len
	 */
	public Map<String, Map<String, Map<String, String>>> getData() {
		final String methodName = "getData():";
		GsonBuilder gsonBuilder = new GsonBuilder();
		gsonBuilder
				.registerTypeAdapter(Object.class, new NaturalDeserializer());
		Gson gson = gsonBuilder.create();
		Reader isReader = null;
		String dataLocation = fileLocation + ".json";
		try {
			isReader = new InputStreamReader(
					new FileInputStream((dataLocation)));
		} catch (FileNotFoundException e) {

			e.printStackTrace();
		}
		Map<String, Map<String, Map<String, String>>> temp = new HashMap<String, Map<String, Map<String, String>>>();
		//
		Object natural = gson.fromJson(isReader, Object.class);
		// // // System.out.println(natural);

		temp.putAll((Map<? extends String, ? extends Map<String, Map<String, String>>>) natural);
		// // // System.out.println(className+methodName+"temp "+temp);
		return temp;
		// // // System.out.println(dataTables.toString());

	}

	/**
	 * tÃ¬m table cÃ³ name tÆ°Æ¡ng á»©ng trong database
	 * 
	 * @param name
	 * @return
	 */
	public Table getTable(String name) {
		int idx = tableExist(name);
		if (idx == -1)
			return null;
		return (Table) dataTables.get(idx);

	}

	/**
	 * Test xem cÃ³ table trong data khong
	 * 
	 * @param name
	 *            tÃªn cá»§a table
	 * @return -1 náº¿u khÃ´ng cÃ³, ngÆ°á»£c láº¡i tráº£ vá»� vá»‹ trÃ­
	 */
	public int tableExist(String name) {
		int length = dataTables.size();
		for (int i = 0; i < length; i++) {
			Table temp = (Table) dataTables.get(i);
			if (temp.getName().equalsIgnoreCase(name))
				return i;
		}
		return -1;
	}

	public Vector getAllTableName() {
		return tableNames;
	}

	/**
	 * Test xem cÃ³ field trong table khong
	 * 
	 * @param fieldName
	 * @param tableName
	 * @return
	 */
	public Boolean fieldExist(String fieldName, String tableName) {
		Table temp = getTable(tableName);
		if (temp == null)
			return false;
		return temp.fieldExit(fieldName);

	}

	/**
	 * Tra ve dong cÃ³ theo vá»‹ trÃ­
	 * 
	 * @param tableName
	 *            tÃªn báº£ng
	 * @param idx
	 *            vá»‹ cá»§a record trong báº£ng
	 * @return kiá»ƒu Map<String,String>
	 */
	public Map<String, Map<String, String>> getRow(String tableName, int idx) {
		Table temp = getTable(tableName);
		return temp.getRow(idx);
	}

	/**
	 * Tra ve dong cÃ³ giÃ¡ trá»‹ tÆ°Æ¡ng á»©ng
	 * 
	 * @param tableName
	 *            tÃªn báº£ng
	 * @param fieldName
	 *            tÃªn field
	 * @param value
	 *            giÃ¡ trá»‹ cá»§a field
	 * @return kiá»ƒu Map chá»©a dÃ²ng tÆ°Æ¡ng á»©ng, ngÆ°á»£c láº¡i tráº£ vá»�
	 *         null
	 */
	public Map<String, Map<String, String>> getRow(String tableName,
			String fieldName, String value) {
		Table temp = getTable(tableName);
		return temp.getRow(fieldName, value);
	}

	public void createTableField(String tableName, String fieldName,
			String fieldType) {
		// TODO Auto-generated method stub
		String methodName = "createTableField():";
		Table temp = getTable(tableName);
		temp.createField(fieldName, fieldType);
		changeTable(temp);
	}

	public void editTableFieldType(String tableName, String fieldName,
			String fieldType) {
		// TODO Auto-generated method stub
		Table temp = getTable(tableName);
		temp.editField(fieldName, fieldType);
		changeTable(temp);
		// editValueAllRecord(tableName, fieldName, "put value...");

	}

	public Map<String, Map<String, String>> getAllRow(String tableName) {
		// TODO Auto-generated method stub
		Table temp = getTable(tableName);
		return temp.getAllRow();
	}

	public void createTable(String tableName) {
		// TODO Auto-generated method stub
		final String methodName = "createTable():";
		DataTableDefination temp = new DataTableDefination(tableName, null,
				null);
		dataDefines.add(temp);
		Table temp1 = new Table(null, tableName);
		// System.out.println(className + methodName + "myData 1:" + myData);
		myData.put(tableName, null);
		// System.out.println(className + methodName + "myData 2:" + myData);
		dataTables.add(temp1);
		save(dataDefines, fileLocation + ".define");
		save(myData, fileLocation + ".json");
	}

	public void removeTable(String tableName) {
		// TODO Auto-generated method stub
		int length = dataDefines.size();
		for (int i = 0; i < length; i++) {

			DataTableDefination temp1 = dataDefines.get(i).getObject(tableName);
			if (temp1 != null) {
				dataDefines.remove(temp1);
				break;
			}
		}
		save(dataDefines, fileLocation + ".define");

	}

	private void xuat(String[] a) {
		System.out.print(className + "xuat(): a :");
		for (String t : a) {
			System.out.print(t + "::");

		}
		System.out.println();
	}

	public int insertRecord(String tableName, String[] fieldName,
			String[] fieldValue) {
		final String methodName = "insertRecord():";

		Table temp = getTable(tableName);
		if (temp == null)
			return -11;
		System.out.println(className + methodName + "mydata():" + myData);

		System.out.println(className + methodName + "temp.getAllFieldName():"
				+ temp.getAllFieldName());
		xuat(fieldName);
		xuat(fieldValue);
		int result = temp.insertRecord(fieldName, fieldValue);
		if (result == 1) {
			myData.put(tableName, temp.getData());

			// TODO Auto-generated method stub
			save(myData, fileLocation + ".json");
		}
		return result;
	}

	public String getTableFieldDefines(String tableName, String fieldName) {
		final String methodName = "getTableDefines():";
		// TODO Auto-generated method stub
		// System.out.println(className + methodName + "1");
		Table temp = getTable(tableName);
		if (temp == null)
			return null;
		String names = temp.getAllFieldName();
		String types = temp.getAllTypes();
		String[] temp1 = names.split(":");
		String[] temp2 = types.split(":");
		int length = temp1.length;
		Map<String, String> result = new HashMap<String, String>();
		for (int i = 0; i < length; i++) {
			if (temp1[i].equalsIgnoreCase(fieldName)) {
				return temp2[i];
			}
		}
		// System.out.println(className + methodName + "result:" + result);
		return null;
	}

	public String getTableName(String tableName) {
		final String methodName = "getTableName():";
		System.out.println(className + methodName + "vao 1");
		System.out.println(className + methodName + "tableName:" + tableName);

		Table temp = getTable(tableName);
		if (temp == null)
			return null;
		System.out.println(className + methodName + "vao 2");

		Vector<String> a = getAllTableName();
		for (String d : a) {
			if (d.equalsIgnoreCase(tableName)) {
				return d;
			}
		}
		return null;

	}

	public String getFieldName(String tableName, String fieldName) {
		Table temp = getTable(tableName);
		if (temp == null)
			return null;
		String names = temp.getAllFieldName();
		String types = temp.getAllTypes();
		String[] temp1 = names.split(":");
		String[] temp2 = types.split(":");
		int length = temp1.length;
		Map<String, String> result = new HashMap<String, String>();
		for (int i = 0; i < length; i++) {
			if (temp1[i].equalsIgnoreCase(fieldName)) {
				return temp1[i];
			}
		}
		return null;
	}

	public Map<String, String> getTableDefines(String tableName) {
		final String methodName = "getTableDefines():";
		// TODO Auto-generated method stub
		// System.out.println(className + methodName + "1");
		String tb = getTableName(tableName);
		Table temp = getTable(tb);
		if (temp == null)
			return null;
		String names = temp.getAllFieldName();
		String types = temp.getAllTypes();
		String[] temp1 = names.split(":");
		String[] temp2 = types.split(":");
		int length = temp1.length;
		Map<String, String> result = new HashMap<String, String>();
		for (int i = 0; i < length; i++) {
			result.put(temp1[i], temp2[i]);
		}
		// System.out.println(className + methodName + "result:" + result);
		return result;
	}

	public void editRecord(int idx, String tableName, String fieldName,
			String fieldValue) {
		// TODO Auto-generated method stub
		final String methodName = "editRecord():";
		// TODO Auto-generated method stub
		// System.out.println(className + methodName + "1");
		Table temp = getTable(tableName);
		if (temp == null)
			return;
		temp.editRecord(idx, tableName, fieldName, fieldValue);
		myData.put(tableName, temp.getData());
		save(myData, fileLocation + ".json");
	}

	public void removeTableField(String tableName, String fieldName) {
		// TODO Auto-generated method stub
		final String methodName = "removeTableField():";
		Table temp = getTable(tableName);
		temp.removeTableFieldData(fieldName);
		temp.removeField(fieldName);
		myData.put(tableName, temp.getData());
		// System.out.println(className + methodName + "myData 1" + myData);
		save(myData, fileLocation + ".json");

		changeTable(temp);
	}

	private void changeTable(Table temp) {
		int length = dataDefines.size();

		for (int i = 0; i < length; i++) {

			DataTableDefination temp1 = dataDefines.get(i).getObject(
					temp.getName());
			if (temp1 != null) {
				dataDefines.remove(temp1);
				temp1.setVarName(temp.getAllFieldName());
				temp1.setTypes(temp.getAllTypes());
				temp1.setPk(temp.getPrimaryKey());
				dataDefines.add(temp1);
			}
		}
		save(dataDefines, fileLocation + ".define");
	}

	public void insetTableField(String tableName, String fieldName,
			String fieldType, Boolean dataExist) {
		// TODO Auto-generated method stub
		String methodName = "createTableField():";
		Table temp = getTable(tableName);
		temp.createField(fieldName, fieldType);
		changeTable(temp);
		if (dataExist) {
			editValueAllRecord(tableName, fieldName, "put value...");
		}
		// System.out.println(className+methodName+"data:" + temp.getData());
	}

	public void deleteTableRecord(String tableName, String rowID) {
		final String methodName = getClass().getSimpleName() + "():";
		System.out.println(className + methodName + "vao 0");
		Table temp = getTable(tableName);
		temp.deleteRecord(rowID);
		myData.put(tableName, temp.getData());
		save(myData, fileLocation + ".json");

	}

	public void removeAllTableField(String tableName) {
		// TODO Auto-generated method stub
		final String methodName = "removeAllTableField():";
		// System.out.println(className + methodName + "myData 1" + myData);

		Table temp = getTable(tableName);

		String[] fields = temp.getAllFieldName().split(":");
		if (fields == null)
			return;
		for (String fieldName : fields) {
			if (!temp.fieldExit(fieldName))
				continue;
			temp.removeTableFieldData(fieldName);
			temp.removeField(fieldName);
			myData.put(tableName, temp.getData());
			// System.out.println(className + methodName + "myData 2" + myData);
			save(myData, fileLocation + ".json");

			changeTable(temp);
		}
	}

	public void editTableFieldName(String tableName, String fieldName,
			String fieldNameNew) {
		// TODO Auto-generated method stub
		final String methodName = "editTableFieldName():";

		Table temp = getTable(tableName);
		if (!temp.fieldExit(fieldName))
			return;
		temp.renameField(fieldName, fieldNameNew);
		changeTable(temp);
		// TODO Auto-generated method stub
		// System.out.println(className + methodName + "1");
		Table table = getTable(tableName);
		if (temp == null)
			return;
		temp.renameAllRecord(fieldName, fieldNameNew);
		myData.put(tableName, temp.getData());
		save(myData, fileLocation + ".json");

	}

	public void removeAllTableRecord(String tableName) {
		// TODO Auto-generated method stub
		final String methodName = "removeAllTableRecord():";
		// System.out.println(className + methodName + "1");

		System.out.println(className + methodName + "đã vào");

		Map<String, Map<String, String>> tt = new HashMap<String, Map<String, String>>();
		// Map<String,Map<String, Map<String, String>>> result = new
		// HashMap<String, Map<String,Map<String,String>>>();

		myData.put(tableName, null);
		// Vector<String> tam = getAllTableName();
		// int length = tam.size();
		// for (int i = 0 ; i<length ; i++)
		// {
		// String name = tam.get(i);
		// if (!name.equalsIgnoreCase(tableName))
		// result.put(name, myData.get(name));
		// else
		// result.put(name, tt);
		// System.out.println(className + methodName + "result" + result);
		//
		// }
		// if (myData == null)
		// return;
		// myData.clear();
		// System.out.println(className + methodName + "myData " + myData );
		// System.out.println(className + methodName + "result 21" + result );

		myData.put(tableName, tt);
		save(myData, fileLocation + ".json");

	}

	public void setTablePrimaryKey(String tableName, Vector keys) {
		// TODO Auto-generated method stub
		Table temp = getTable(tableName);
		temp.setPrimaryKey(keys);
		changeTable(temp);
	}

	public Vector<String> getTablePrimaryKey(String tableName) {
		// TODO Auto-generated method stub
		Table temp = getTable(tableName);
		return temp.getPrimaryKey();
	}

	public void removeTablePrimaryKey(String tableName) {
		// TODO Auto-generated method stub
		Table temp = getTable(tableName);
		temp.removePrimaryKey();
		changeTable(temp);
	}

}
